package controllers

import (
	"fmt"
	"io/fs"
	"log"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"

	"easy-gin/configs"
	"easy-gin/models"
	"easy-gin/utils"

	"github.com/gin-gonic/gin"
)

const fileSeparator = string(os.PathSeparator)

func GetFilesFromSql(ctx *gin.Context) {
	page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(ctx.DefaultQuery("page_size", "20"))
	fileType, _ := strconv.Atoi(ctx.DefaultQuery("file_type", "4"))

	files, _ := models.GetSqlFilesInfo(fileType, page, pageSize)

	var dir = models.GetTable(fileType)

	proto, port := getProtoAndPortStr(ctx)

	var result = "["

	for _, file := range files {
		if strings.HasPrefix(file.Name, ".") {
			continue
		}
		result += "\"" + proto + utils.Ip + ":" + port + configs.UploadPathKey + "/" + dir + "/" + file.Name + "\","
	}

	result = result[0:(len(result) - 1)]
	result += "]"
	// fmt.Println(result)
	ctx.String(http.StatusOK, result)
}

// 上传单个文件
func UpdaloadFile(c *gin.Context) {
	file, err := c.FormFile("file")
	if err != nil {
		c.String(500, "上传图片出错")
	}
	path := fileSeparator + "other" + fileSeparator
	if strings.HasSuffix(file.Filename, ".mp4") || strings.HasSuffix(file.Filename, ".mov") || strings.HasSuffix(file.Filename, ".mkv") {
		path = fileSeparator + "videos" + fileSeparator
	} else if strings.HasSuffix(file.Filename, ".wav") || strings.HasSuffix(file.Filename, ".flac") || strings.HasSuffix(file.Filename, ".ape") || strings.HasSuffix(file.Filename, ".mp3") {
		path = fileSeparator + "musics" + fileSeparator
	} else if strings.HasSuffix(file.Filename, ".jpg") || strings.HasSuffix(file.Filename, ".jpeg") || strings.HasSuffix(file.Filename, ".png") || strings.HasSuffix(file.Filename, ".gif") {
		path = fileSeparator + "images" + fileSeparator
	} else if strings.HasSuffix(file.Filename, ".txt") || strings.HasSuffix(file.Filename, ".pdf") || strings.HasSuffix(file.Filename, ".doc") || strings.HasSuffix(file.Filename, ".docx") || strings.HasSuffix(file.Filename, ".excel") {
		path = fileSeparator + "docs" + fileSeparator
	}

	var saveName = strings.Replace(file.Filename, " ", "", -1)

	// c.JSON(200, gin.H{"message": file.Header.Context})
	saveErr := c.SaveUploadedFile(file, configs.UpdaloadPath+path+saveName)
	if saveErr != nil {
		c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", saveErr.Error()))
		return
	}
	c.String(http.StatusOK, file.Filename)
	// c.Redirect(http.StatusMovedPermanently, "http://"+utils.Ip+":8080/upload/images.html")
	// proto, port := getProtoAndPortStr(c)

	// c.Redirect(http.StatusMovedPermanently, proto+utils.Ip+":"+port+configs.UploadPathKey+"/fileIndex.html")
}

// 上传多个文件
func UploadMultiFile(c *gin.Context) {
	form, err := c.MultipartForm()
	if err != nil {
		c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
	}
	// 获取所有图片
	files := form.File["files"]

	var path = fileSeparator + "other" + fileSeparator
	var fileType = models.FILE_TYPE_OTHER
	// 遍历所有图片
	for _, file := range files {
		var name = strings.ToLower(file.Filename)
		if strings.HasSuffix(name, ".mp4") || strings.HasSuffix(name, ".mov") || strings.HasSuffix(name, ".mkv") {
			path = fileSeparator + "videos" + fileSeparator
			fileType = models.FILE_TYPE_VIDEO
		} else if strings.HasSuffix(name, ".wav") || strings.HasSuffix(name, ".flac") || strings.HasSuffix(name, ".ape") || strings.HasSuffix(name, ".mp3") || strings.HasSuffix(name, ".aac") {
			path = fileSeparator + "musics" + fileSeparator
			fileType = models.FILE_TYPE_MUSIC
		} else if strings.HasSuffix(name, ".jpg") || strings.HasSuffix(name, ".jpeg") || strings.HasSuffix(name, ".png") || strings.HasSuffix(name, ".gif") || strings.HasSuffix(name, ".webp") {
			path = fileSeparator + "images" + fileSeparator
			fileType = models.FILE_TYPE_IMAGE
		} else if strings.HasSuffix(name, ".txt") || strings.HasSuffix(name, ".pdf") || strings.HasSuffix(name, ".doc") || strings.HasSuffix(name, ".docx") || strings.HasSuffix(name, ".excel") {
			path = fileSeparator + "docs" + fileSeparator
			fileType = models.FILE_TYPE_DOC
		} else {
			path = fileSeparator + "other" + fileSeparator
		}

		var saveName = strings.Replace(file.Filename, " ", "", -1)

		//创建文件
		// out, err := os.Create(configs.UpdaloadPath + path + file.Filename)

		// if err != nil {
		// 	log.Fatal(err)
		// }
		// defer out.Close()

		// _, err = io.Copy(out, file)

		// if  err != nil {
		// 	c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
		// 	return
		// }

		// 逐个存
		if err := c.SaveUploadedFile(file, configs.UpdaloadPath+path+saveName); err != nil {
			c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
			return
		}

		models.AddSqlFileInfo(fileType, saveName, file.Size)
	}

	proto, port := getProtoAndPortStr(c)
	c.Redirect(http.StatusMovedPermanently, proto+utils.Ip+":"+port+configs.UploadPathKey+"/fileIndex.html")
	// c.String(200, fmt.Sprintf("upload ok %d files", len(files)))
}

// 获取图片文件列表
func GetFiles(c *gin.Context) {
	path := c.DefaultQuery("path", "/")

	files, err := os.ReadDir(configs.UpdaloadPath + path)
	if err != nil {
		log.Fatal(err)
		return
	}

	bubbleSort(&files)

	returnReusltList(files, c, path)
}

// 获取图片文件列表
func GetImages(c *gin.Context) {
	files, err := os.ReadDir(configs.UpdaloadPath + "images")
	if err != nil {
		log.Fatal(err)
		return
	}

	bubbleSort(&files)

	returnReusltList(files, c, "images")
}

// 获取音乐文件列表
func GetMusics(c *gin.Context) {
	files, err := os.ReadDir(configs.UpdaloadPath + "musics")
	if err != nil {
		log.Fatal(err)
		return
	}

	//音乐、视频、文档等按名称排序
	// sortByName(&files)
	returnReusltList(files, c, "musics")
}

// 获取视频文件列表
func GetVideos(c *gin.Context) {
	files, err := os.ReadDir(configs.UpdaloadPath + "videos")
	if err != nil {
		log.Fatal(err)
		return
	}

	// sortByName(&files)
	returnReusltList(files, c, "videos")
}

// 获取文档文件列表
func GetDocs(c *gin.Context) {
	files, err := os.ReadDir(configs.UpdaloadPath + "docs")
	if err != nil {
		log.Fatal(err)
		return
	}

	// bubbleSort(&files)
	returnReusltList(files, c, "docs")
}

// 获取其他类型文件列表
func GetOtherFiles(c *gin.Context) {
	files, err := os.ReadDir(configs.UpdaloadPath + "other")
	if err != nil {
		log.Fatal(err)
		return
	}

	// sortByName(&files)
	returnReusltList(files, c, "other")
}

// func SearchFiles(c *gin.Context) {
// 	fileType := c.Query("type")
// 	keyWords := c.Query("keyWords")
// 	path := "/"
// 	switch fileType {
// 	case "image":
// 		path = "images"
// 		break
// 	case "music":
// 		path = "musics"
// 		break
// 	case "video":
// 		path = "videos"
// 		break
// 	case "doc":
// 		path = "docs"
// 		break
// 	case "other":
// 		path = "other"
// 		break
// 	}

// 	files, err := os.ReadDir(configs.UpdaloadPath + path)
// 	if err != nil {
// 		log.Fatal(err)
// 		return
// 	}

// 	result  = []

// 	// sortByName(&files)
// 	returnReusltList(files, c, "other")

// }

// 给客户端返回文件列表
func returnReusltList(files []fs.DirEntry, c *gin.Context, dir string) {
	proto, port := getProtoAndPortStr(c)

	var result = "["

	if len(files) > 0 {
		for _, file := range files {
			if strings.HasPrefix(file.Name(), ".") {
				continue
			}
			result += "\"" + proto + utils.Ip + ":" + port + configs.UploadPathKey + "/" + dir + "/" + file.Name() + "\","
			// fmt.Println(file.Name())
		}

		result = result[0:(len(result) - 1)]
	}

	result += "]"
	// fmt.Println(result)
	c.String(http.StatusOK, result)
}

// 按修改时间冒泡排序文件
func bubbleSort(arr *[]fs.DirEntry) {
	// fmt.Println("排序前：", (*arr))
	// 总结规律：先内层(每一轮)再外层,内层n-1-i次,外层n-1
	var temp fs.DirEntry
	for i := 0; i < len(*arr)-1; i++ {
		for j := 0; j < len(*arr)-1-i; j++ {
			var currentInfo, _ = ((*arr)[j]).Info()
			var otherInfo, _ = ((*arr)[j+1]).Info()
			if currentInfo.ModTime().Unix() < otherInfo.ModTime().Unix() {
				temp = (*arr)[j]
				(*arr)[j] = (*arr)[j+1]
				(*arr)[j+1] = temp
			}
		}
	}
}

func sortByName(arr *[]fs.FileInfo) {
	arrValue := (*arr)
	sort.Slice(arrValue, func(i, j int) bool {
		return arrValue[i].Name() < arrValue[j].Name()
	})
}

// 获取磁盘信息，总容量及已使用未使用容量
func GetDiskInfo(ctx *gin.Context) {
	diskInfo := utils.DiskUsage(string(os.PathSeparator))
	ctx.JSON(http.StatusOK, gin.H{
		"all":  diskInfo.All,
		"free": diskInfo.Free,
		"used": diskInfo.Used,
	})
}

// 根据是否是https获取proto及port信息
func getProtoAndPortStr(ctx *gin.Context) (proto string, port string) {
	if ctx.Request.TLS != nil {
		proto = "https://"
		port = configs.HttpsPort
		return
	} else {
		proto = "http://"
		port = configs.Port
		return
	}
}
